package com.cloudkinto.service.platform.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.annotate.GraphqlResultAttributesBuilder;
import com.cloudkinto.bo.order.makeshop.MakeShopShopConfig;
import com.cloudkinto.bo.order.makeshop.getOrder.*;
import com.cloudkinto.bo.order.makeshop.updateOrderAttribute.*;
import com.cloudkinto.bo.order.makeshop.updateOrderDeliveryStatus.*;
import com.cloudkinto.common.RabbitQueueConstant;
import com.cloudkinto.common.RedisKeyConstants;
import com.cloudkinto.common.common.DateUtils;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.utils.OkHttpUtils;
import com.cloudkinto.common.utils.dict.StaticDict;
import com.cloudkinto.dao.PlatformOrderDao;
import com.cloudkinto.dao.PlatformOrderProductDao;
import com.cloudkinto.dao.PlatformStoreDao;
import com.cloudkinto.entity.OperateRecordDo;
import com.cloudkinto.entity.PlatformOrderDo;
import com.cloudkinto.entity.PlatformOrderProductDo;
import com.cloudkinto.entity.PlatformStoreDo;
import com.cloudkinto.enumType.common.CountryEnum;
import com.cloudkinto.enumType.operate.OperateTypeEnum;
import com.cloudkinto.service.consumer.vo.makeshop.MakeShopMarkStatusConsumerReq;
import com.cloudkinto.service.consumer.vo.makeshop.MakeShopMarkShipConsumerReq;
import com.cloudkinto.service.consumer.vo.makeshop.MakeShopOrderUpdateConsumerReq;
import com.cloudkinto.service.consumer.vo.makeshop.MakeshopConsumerReq;
import com.cloudkinto.service.platform.PlatformOrderMakeshopSyncService;
import com.cloudkinto.service.platform.PlatformOrderService;
import com.cloudkinto.service.platform.PlatformStoreService;
import com.cloudkinto.service.platform.vo.store.StoreMakeshopAddReq;
import com.cloudkinto.utils.MakeShopGraphqlUtils;
import lombok.RequiredArgsConstructor;
import okhttp3.*;
import org.apache.commons.lang.StringUtils;
import org.mountcloud.graphql.request.param.RequestObjectParameter;
import org.mountcloud.graphql.request.result.ResultAttributtes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author ding
 * @since 2021-09-23
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
@RequiredArgsConstructor
public class PlatformOrderMakeshopSyncServiceImpl extends ServiceImpl<PlatformOrderDao, PlatformOrderDo> implements PlatformOrderMakeshopSyncService {
    private final PlatformStoreDao platformStoreDao;
    private final PlatformOrderDao platformOrderDao;
    private final RabbitTemplate rabbitTemplate;
    private final PlatformOrderProductDao platformOrderProductDao;
    private final PlatformOrderService platformOrderService;
    private final PlatformStoreService platformStoreService;
    private final RedisTemplate redisTemplate;
    @Value("${gbc.auth.redirectURL}")
    private String redirectURL;
    @Value("${gbc.customer}")
    private String customer;

    protected Logger log = LoggerFactory.getLogger(AmazonBaseServiceImpl.class);

    protected String AUTHORIZESTATEKEY = "makeshop_authorize_state_";
    /**
     * ===========================Shopify参数================================
     */
    protected String MakeshopClientSecret = "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";
    protected String MakeshopClientId = "fd5b9cb19a9ab8d8223bf2f5283d3740";

    protected String x_api_key = "x-api-key	";//申请“应用程序开发”和“应用程序发布申请”后，我们将向您发出并通知您。

    /**
     * shopify授权第一步 返回给前端跳转的url
     */
    @Override
    public String authorizeNow(StoreMakeshopAddReq req, Long userId, Long companyId) {
        boolean check = platformStoreService.check(req.getId(), req.getStoreCode(), companyId);
        if (!check) {
            throw new BizException("店铺代码已存在");
        }
        if (req.getId() != null) {
            PlatformStoreDo storeDo = platformStoreService.getById(req.getId());
            if (storeDo == null || !Objects.equals(storeDo.getCompanyId(), companyId)) {
                throw new BizException("店铺不存在");
            }
        }
        String state = UUID.randomUUID().toString();
        //放入缓存
        redisTemplate.opsForValue().set(AUTHORIZESTATEKEY + userId, state, 3000, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(state, JSON.toJSONString(req), 3000, TimeUnit.SECONDS);
        StringBuilder builderUrl = new StringBuilder();
        builderUrl.append("https://console.makeshop.jp/apps/sso")
                .append("?response_type=code")
                .append("&clientId=").append(MakeshopClientId)
                .append("&redirect_uri=").append(redirectURL)
                .append("&state=").append(state);
//                .append("nonce=makeshop");
        //todo redirect_uri 值不知道是什么
        return builderUrl.toString();
    }

    public static String getBase64ESA(String secret, String license) {
        byte[] pass = (secret.trim() + ":" + license.trim()).getBytes(StandardCharsets.UTF_8);
        return "Basic " + Base64.getEncoder().encodeToString(pass);
    }

    public void getMakeshopAuthorizeMsg(String code, String scope, String state, String error, String error_description, Long userId, Long companyId) {
        if (StringUtils.isNotBlank(error)) {
            throw new BizException(error + ":" + error_description);
        }
        Object value = redisTemplate.opsForValue().get(state);
        if (value == null) {
            throw new BizException("未找到店铺,授权失败");
        }
        StoreMakeshopAddReq storeShopifyAddReq = JSON.parseObject(value.toString(), StoreMakeshopAddReq.class);
        Map<String, String> params = new HashMap<>();
        params.put("grant_type", "authorization_code");
        params.put("client_id", MakeshopClientId);
        params.put("code", code);
        params.put("redirect_uri", redirectURL);
        String url = "https://app-auth.makeshop.jp/oauth2/token";
        String body = this.doPostOAuth(url, params);
        if (StringUtils.isNotBlank(body)) {
            throw new BizException("连接超时,maekshop授权失败");
        }
        JSONObject jsonObject = JSON.parseObject(body);
        String accessToken = jsonObject.getString("access_token");
        String errorRes = jsonObject.getString("error");
        if (StringUtils.isNotBlank(errorRes)) {
            throw new BizException(errorRes + ":" + jsonObject.get("error_description"));
        } else if (StringUtils.isNotBlank(accessToken)) {
            throw new BizException("无accessToken,，makeshop授权失败");
        }
        PlatformStoreDo storeDo;
        if (storeShopifyAddReq.getId() == null) {
            storeDo = platformStoreService.maekshopStoreAdd(storeShopifyAddReq, userId, companyId);
        } else {
            storeDo = platformStoreService.getById(storeShopifyAddReq.getId());
            if (!Objects.equals(storeDo.getCompanyId(), companyId)) {
                throw new BizException("店铺不存在,makeshop授权失败");
            }
        }
        String refresh_token = jsonObject.getString("refresh_token");
        //ユーザが認証されたことを証明するためのトークンです。
        //nonceの検証はこのトークンをJWTデコードしたJSON の nonce と SSO ログイン URLのnonce と一致するか確認します。
        //
        //※JWSの検証をする場合、以下のURLよりJWK Setを取得してください。
        //auth-facadeのurl/.well-known/jwks.json
        String id_token = jsonObject.getString("id_token");
        storeDo.setAppSecret(refresh_token);
        storeDo.setAuthSyncStatus(1);
        storeDo.setAuthSyncTime(new Date());
        platformStoreDao.updateById(storeDo);
        Long expires_in = jsonObject.getLong("expires_in");
        redisTemplate.opsForValue().set(RedisKeyConstants.MAKESHOPACCESSTOKEN_STORE + storeDo.getId(), accessToken, expires_in - 30, TimeUnit.SECONDS);

    }


    public String getAccessToken(PlatformStoreDo storeDo) {
        String accessToken = (String) redisTemplate.opsForValue().get(RedisKeyConstants.MAKESHOPACCESSTOKEN_STORE + storeDo.getId());
        if (accessToken != null) {
            return accessToken;
        }
        if (storeDo.getAppSecret() == null) {
            return null;
        }
        Map<String, String> params = new HashMap<>();
        params.put("grant_type", "refresh_token");
        params.put("client_id", MakeshopClientId);
        params.put("refresh_token", storeDo.getAppSecret());
        String url = "https://app-auth.makeshop.jp/oauth2/token";
        String body = this.doPostOAuth(url, params);
        if (StringUtils.isNotBlank(body)) {
            log.error("MakeShop 用刷新令牌获取 临时令牌错误:连接超时");
            return null;
        }
        JSONObject jsonObject = JSON.parseObject(body);
        accessToken = jsonObject.getString("access_token");
        if (StringUtils.isNotBlank(accessToken)) {
            Long expires_in = jsonObject.getLong("expires_in");
            redisTemplate.opsForValue().set(RedisKeyConstants.MAKESHOPACCESSTOKEN_STORE + storeDo.getId(), accessToken, expires_in - 30, TimeUnit.SECONDS);
        } else {
            String errorRes = jsonObject.getString("error");
            log.error("MakeShop 用刷新令牌获取 临时令牌错误:" + errorRes + ":" + jsonObject.get("error_description"));
            //todo 过期的情况
        }
        return accessToken;
    }


    public String doPostOAuth(String url, Map<String, String> params) {
        String body = "";
        InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 10809);
        Proxy proxy = new Proxy(Proxy.Type.HTTP, addr); // http 代理
        OkHttpClient.Builder client = OkHttpUtils.getUnsafeOkHttpClient().newBuilder();
        client.connectTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
//                        .proxy(proxy)
                .retryOnConnectionFailure(true);
        Request request = new Request.Builder()
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .addHeader("Authorization", getBase64ESA(MakeshopClientId, MakeshopClientSecret))
                .post(RequestBody.create(MediaType.get("application/json"), JSON.toJSONString(params))).url(url).build();
        Response response = null;
        try {
            response = client.build().newCall(request).execute();
            if (response.body() != null) {
                body = response.body().string();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return body;
    }


    public String doPost(PlatformStoreDo storeDo, String url, Map<String, Object> params) {
        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("content-type", "application/json");
        headerMap.put("authorization", getAccessToken(storeDo));
        headerMap.put("x-api-key", x_api_key);
        headerMap.put("x-timestamp", String.valueOf(new Date().getTime() / 1000));

        String body = "";
        InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 10809);
        Proxy proxy = new Proxy(Proxy.Type.HTTP, addr); // http 代理
        OkHttpClient.Builder client = OkHttpUtils.getUnsafeOkHttpClient().newBuilder();
        client.connectTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
//                        .proxy(proxy)
                .retryOnConnectionFailure(true);
        Request.Builder requestBuilder = createSPHeader(headerMap);
        Request request = requestBuilder.url(url)
                .post(RequestBody.create(MediaType.get("application/json"), JSON.toJSONString(params))).build();
        Response response = null;
        try {
            response = client.build().newCall(request).execute();
            if (response.body() != null) {
                body = response.body().string();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return body;
    }


    @Override
    public void platOrderMakeShopSync() {
        List<PlatformStoreDo> storeDoList = platformStoreDao.selectList(new LambdaQueryWrapper<PlatformStoreDo>().eq(PlatformStoreDo::getPlatformCode, "makeshop").eq(PlatformStoreDo::getStoreStatus, 1).eq(PlatformStoreDo::getAuthSyncStatus, 1));
        for (PlatformStoreDo platformStoreDo : storeDoList) {
            MakeshopConsumerReq consumerReq = new MakeshopConsumerReq(platformStoreDo.getId(), null, null, null);
            rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_MakeShop_Sync, JSON.toJSONString(consumerReq));
        }
    }

    @Override
    public String updateMakeShopOrders(MakeshopConsumerReq req) {
        PlatformStoreDo storeDo = platformStoreDao.selectById(req.getStoreId());
        if (storeDo == null || StringUtils.isBlank(storeDo.getShopUrl()) || StringUtils.isBlank(storeDo.getAppKey()) || StringUtils.isBlank(storeDo.getServiceToken())) {
            return ("店铺未通过Make Shop授权");
        }
        SearchOrderRequest searchOrderRequest = new SearchOrderRequest();
        searchOrderRequest.setPage(1);
        searchOrderRequest.setLimit(1000);
        ResultAttributtes[] resultAttributtes = GraphqlResultAttributesBuilder.build(SearchOrderResponse.class);
        if (StringUtils.isNotBlank(req.getDisplayOrderNumber())) {
            searchOrderRequest.setDisplayOrderNumber(req.getDisplayOrderNumber());
        }
        //手动指定时间区间
        if (req.getBeginTime() != null && req.getEndTime() != null) {
            //判断日期跨度不能太长
            long l = DateUtil.betweenDay(req.getBeginTime(), req.getEndTime(), true);
            if (l > 7) {
                return "店铺:" + storeDo.getStoreName() + "每次最多同步7天数据";
            }
            searchOrderRequest.setStartOrderDate(DateUtils.dateFormatToString(req.getBeginTime(), "yyyyMMddHHmmss"));
            searchOrderRequest.setEndOrderDate(DateUtils.dateFormatToString(req.getEndTime(), "yyyyMMddHHmmss"));
        } else {
            //默认同步当天数据
            String date = DateUtil.format(DateUtil.date(), "yyyyMMdd");
            searchOrderRequest.setStartOrderDate(date + "000000");
            searchOrderRequest.setEndOrderDate(date + "235959");
        }
        int searchedCount;
        int page = 1;
        List<SearchedOrder> orders = new ArrayList<>();
        do {
            searchOrderRequest.setPage(page++);
            Map<String, Object> request = new HashMap<>(2);
            request.put("input", new RequestObjectParameter(searchOrderRequest));
            SearchOrderResponse searchOrder;
            try {
                searchOrder = MakeShopGraphqlUtils.postGraphqlQuery(MakeShopShopConfig.builder().url(storeDo.getShopUrl()).apiKey(storeDo.getAppKey()).token(storeDo.getServiceToken()).build(), "searchOrder", request, SearchOrderResponse.class, resultAttributtes);
            } catch (Exception e) {
                return "店铺【" + storeDo.getStoreName() + "】同步订单失败，" + e.getMessage();
            }
//            redisTemplate.opsForZSet().add(RedisKeyConstants.orderSyncTimeSet_Makeshop + customer, storeDo.getId(), req.getBeginTime().getTime());
            searchedCount = searchOrder.getSearchedCount();
            if (CollUtil.isNotEmpty(searchOrder.getOrders())) {
                orders.addAll(searchOrder.getOrders());
            }
        } while (searchedCount >= 1000);

        if (CollUtil.isNotEmpty(orders)) {
            // 获取平台订单号
            List<String> platNoList = orders.stream().map(SearchedOrder::getDisplayOrderNumber).collect(Collectors.toList());
            // 查询库内平台订单
            Map<String, PlatformOrderDo> platNoMatchOrder = new HashMap<>();
            if (CollUtil.isNotEmpty(platNoList)) {
                List<List<String>> partition = ListUtil.partition(platNoList, 2000);
                for (List<String> list : partition) {
                    List<PlatformOrderDo> platformOrderDos = platformOrderService.lambdaQuery()/*.select(PlatformOrderDo::getPlatformOrderNo, PlatformOrderDo::getId, PlatformOrderDo::getPlatformCode, PlatformOrderDo::getLastUpdateDate)*/.eq(PlatformOrderDo::getPlatformCode, StaticDict.Store_PlatformCode.Makeshop.getValue()).in(PlatformOrderDo::getPlatformOrderNo, list).list();
                    if (CollUtil.isNotEmpty(platformOrderDos)) {
                        platNoMatchOrder.putAll(platformOrderDos.stream().collect(Collectors.toMap(PlatformOrderDo::getPlatformOrderNo, val -> val, (o1, o2) -> o1)));
                    }
                }
            }
            //要插入的
            List<PlatformOrderDo> platInertList = new ArrayList<>();
            List<PlatformOrderDo> platUpdateList = new ArrayList<>();
            //子表插入的
            List<PlatformOrderProductDo> platInsetItems = new ArrayList<>();
            List<PlatformOrderProductDo> platUpdateItems = new ArrayList<>();
            for (SearchedOrder searchedOrder : orders) {
                PlatformOrderDo platformOrderDo = this.buildCommonOrderInfo(searchedOrder, storeDo);
                // 平台订单号匹配本地数据
                PlatformOrderDo existPlatOrder = platNoMatchOrder.get(searchedOrder.getDisplayOrderNumber());
                //判断更新时间，如果本地更新时间小于平台更新时间，更新本地订单
                if (Objects.nonNull(existPlatOrder) && Objects.nonNull(existPlatOrder.getLastUpdateDate()) && existPlatOrder.getLastUpdateDate().getTime() >= DateUtil.parse(searchedOrder.getModified(), "yyyyMMddHHmmss").getTime()) {
                    continue;
                }
                if (Objects.nonNull(existPlatOrder)) {
                    platformOrderDo.setId(existPlatOrder.getId());
                }
                //配送信息
                List<DeliveryInfo> deliveryInfos = searchedOrder.getDeliveryInfos();
                //按配送状态分
                Map<String, DeliveryInfo> deliveryStatusMap = deliveryInfos.stream()
                        .filter(i -> StrUtil.isNotBlank(i.getDeliveryStatus()))
                        .collect(Collectors.toMap(DeliveryInfo::getDeliveryStatus, val -> val, (o1, o2) -> o1));
                /*
                  配送状态 N：未処理 Y：配送完了 C：キャンセル R：返送
                 */
                if (deliveryStatusMap.containsKey("C")) {
                    // todo 状态流转wms？？
                    //订单取消方式
                    platformOrderDo.setCancelWay(0);
                    platformOrderDo.setStatus(StaticDict.Platform_Order_Status.Four.getValue());
                    DeliveryInfo deliveryInfo = deliveryStatusMap.get("C");
                    this.buildOrderProductInfoAndDeliveryInfo(platformOrderDo, deliveryInfo, platInsetItems, platUpdateItems);
                } else if (deliveryStatusMap.containsKey("Y")) {
                    platformOrderDo.setStatus(StaticDict.Platform_Order_Status.Three.getValue());
                    DeliveryInfo deliveryInfo = deliveryStatusMap.get("Y");
                    this.buildOrderProductInfoAndDeliveryInfo(platformOrderDo, deliveryInfo, platInsetItems, platUpdateItems);
                } else if (deliveryStatusMap.containsKey("N")) {
                    platformOrderDo.setStatus(StaticDict.Platform_Order_Status.Zero.getValue());
                    DeliveryInfo deliveryInfo = deliveryStatusMap.get("N");
                    this.buildOrderProductInfoAndDeliveryInfo(platformOrderDo, deliveryInfo, platInsetItems, platUpdateItems);
                } else if (deliveryStatusMap.containsKey("R")) {
                    platformOrderDo.setStatus(StaticDict.Platform_Order_Status.Three.getValue());
                    DeliveryInfo deliveryInfo = deliveryStatusMap.get("R");
                    this.buildOrderProductInfoAndDeliveryInfo(platformOrderDo, deliveryInfo, platInsetItems, platUpdateItems);
                }
                if (Objects.nonNull(existPlatOrder)) {
                    platUpdateList.add(platformOrderDo);
                } else {
                    platInertList.add(platformOrderDo);
                }
            }
            if (CollUtil.isNotEmpty(platInertList)) {
                platformOrderService.matchSystemSku(platInsetItems, storeDo.getId(), storeDo.getCompanyId(), storeDo.getTenantId());
                Map<String, List<PlatformOrderProductDo>> skuMap = platInsetItems.stream().filter(i -> StringUtils.isNotBlank(i.getSku())).collect(Collectors.groupingBy(PlatformOrderProductDo::getPlatformOrderNo));
                List<PlatformOrderDo> insertList = platInertList.stream().filter(i -> skuMap.containsKey(i.getPlatformOrderNo())).collect(Collectors.toList());
                for (PlatformOrderDo orderDo : insertList) {
                    if (skuMap.get(orderDo.getPlatformOrderNo()) == null) {
                        continue;
                    }
                    StringBuilder builder = new StringBuilder();
                    for (PlatformOrderProductDo productDo : skuMap.get(orderDo.getPlatformOrderNo())) {
                        if (StringUtils.isNotBlank(builder.toString())) {
                            builder.append(";");
                        }
                        builder.append(productDo.getSku()).append("*").append(productDo.getQty());
                    }
                    if (builder.length() > 100) {
                        builder.delete(100, builder.length());
                    }
                    orderDo.setSku(builder.toString());
                }
                List<List<PlatformOrderDo>> orderPartition = ListUtil.partition(platInertList, 2000);
                for (List<PlatformOrderDo> orderDoList : orderPartition) {
                    platformOrderDao.insertPlatformOrder(orderDoList);
                }
                Map<String, Long> platNoMatchId = platInertList.stream().collect(Collectors.toMap(PlatformOrderDo::getPlatformOrderNo, PlatformOrderDo::getId));
                platInsetItems.forEach(i -> i.setOrderId(platNoMatchId.get(i.getPlatformOrderNo())));
                List<List<PlatformOrderProductDo>> itemPartition = ListUtil.partition(platInsetItems, 2000);
                for (List<PlatformOrderProductDo> orderProductDoList : itemPartition) {
                    platformOrderProductDao.insertPlatformOrderItems(orderProductDoList);
                }
            }
            if (CollUtil.isNotEmpty(platUpdateList)) {
                //再交给rabbitMq 去更新子表
                rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_MakeShop_Update, JSON.toJSONString(new MakeShopOrderUpdateConsumerReq(platUpdateList, platUpdateItems, storeDo.getId(), storeDo.getCompanyId(), storeDo.getTenantId())));
            }
        }
        return null;
    }

    /**
     * 构建订单基本信息
     *
     * @param searchedOrder 请求返回订单信息
     * @return 平台订单对象
     */
    private PlatformOrderDo buildCommonOrderInfo(SearchedOrder searchedOrder, PlatformStoreDo storeDo) {
        PlatformOrderDo platformOrderDo = new PlatformOrderDo();
        if (Objects.isNull(searchedOrder)) {
            return platformOrderDo;
        }
        platformOrderDo.setReserveFlag(0);
        platformOrderDo.setOrderNo(searchedOrder.getSystemOrderNumber());
        platformOrderDo.setPlatformOrderNo(searchedOrder.getDisplayOrderNumber());
        platformOrderDo.setPlatformCode(StaticDict.Store_PlatformCode.Makeshop.getValue());
        platformOrderDo.setStoreId(storeDo.getId());
        platformOrderDo.setCompanyId(storeDo.getCompanyId());
        platformOrderDo.setTenantId(storeDo.getTenantId());
        platformOrderDo.setBuyerName(searchedOrder.getSenderName());
        platformOrderDo.setBuyerEmail(searchedOrder.getSenderEmail());
        platformOrderDo.setBuyerPostcode(searchedOrder.getSenderPost());
        platformOrderDo.setBuyerTelephone(searchedOrder.getSenderTel());
        String buyerAddress = (StrUtil.isNotBlank(searchedOrder.getSenderPrefecture()) ? searchedOrder.getSenderPrefecture() : "")
                + (StrUtil.isNotBlank(searchedOrder.getSenderAddress()) ? searchedOrder.getSenderAddress() : "")
                + (StrUtil.isNotBlank(searchedOrder.getSenderAddress2()) ? searchedOrder.getSenderAddress2() : "");
        platformOrderDo.setBuyerAddress(buyerAddress);
        platformOrderDo.setTotalAmount(BigDecimal.valueOf(searchedOrder.getSumPrice()));
        platformOrderDo.setCurrencyCode(CountryEnum.JP.getCurrency());
        if (StrUtil.isNotBlank(searchedOrder.getOrderDate())) {
            if (DateUtils.regexCheckDateTime1(searchedOrder.getOrderDate())) {
                platformOrderDo.setOrderTime(DateUtil.parse(searchedOrder.getOrderDate(), "yyyy-MM-dd HH:mm:ss"));
            }
        }
        if (StrUtil.isNotBlank(searchedOrder.getModified())) {
            if (DateUtils.regexCheckDateTime2(searchedOrder.getModified())) {
                platformOrderDo.setLastUpdateDate(DateUtil.parse(searchedOrder.getModified(), "yyyyMMddHHmmss"));
            }
        }
        if (StrUtil.isNotBlank(searchedOrder.getPaymentDate())) {
            if (DateUtils.regexCheckDateTime1(searchedOrder.getPaymentDate())) {
                platformOrderDo.setPayTime(DateUtil.parse(searchedOrder.getPaymentDate(), "yyyy-MM-dd HH:mm:ss"));
            }
        }
        platformOrderDo.setSource("api");
        platformOrderDo.setSettlementModel(searchedOrder.getPayMethod());
        return platformOrderDo;
    }

    /**
     * 构建订单商品信息及配送信息（收件人信息等等）
     */
    private void buildOrderProductInfoAndDeliveryInfo(PlatformOrderDo platformOrderDo, DeliveryInfo deliveryInfo, List<PlatformOrderProductDo> platInsetItems, List<PlatformOrderProductDo> platUpdateItems) {
        platformOrderDo.setReceiver(deliveryInfo.getReceiverName());
        platformOrderDo.setBasketId(deliveryInfo.getDeliveryId());
        platformOrderDo.setTelephone(deliveryInfo.getReceiverTel());
        platformOrderDo.setCountryRegionCode(CountryEnum.JP.getValue());
        platformOrderDo.setDistrict(deliveryInfo.getReceiverPrefecture());
        platformOrderDo.setCityCode(deliveryInfo.getReceiverAddress());
        platformOrderDo.setAddressOne(deliveryInfo.getReceiverAddress2());
        platformOrderDo.setPostcode(deliveryInfo.getReceiverPost());
        if (StrUtil.isNotBlank(deliveryInfo.getEstimatedShipmentDate())) {
            if (DateUtils.regexCheckDateTime1(deliveryInfo.getEstimatedShipmentDate())) {
                platformOrderDo.setShipTime(DateUtil.parse(deliveryInfo.getEstimatedShipmentDate(), "yyyy-MM-dd HH:mm:ss"));
            }
        }
        if (StrUtil.isNotBlank(deliveryInfo.getDesiredDeliveryDate())) {
            platformOrderDo.setDeliveryDate(deliveryInfo.getDesiredDeliveryDate());
        }
        if (StrUtil.isNotBlank(deliveryInfo.getDesiredDeliveryTimezone())) {
            platformOrderDo.setDeliveryTimeName(deliveryInfo.getDesiredDeliveryTimezone());
        }
        if (StrUtil.isNotBlank(deliveryInfo.getSlipNumber())) {
            platformOrderDo.setTrackNo(deliveryInfo.getSlipNumber());
        }
        platformOrderDo.setPostagePrice(BigDecimal.valueOf(deliveryInfo.getShippingCharge()));
        List<BasketInfo> basketInfoList = deliveryInfo.getBasketInfos();
        if (CollUtil.isEmpty(basketInfoList)) {
            return;
        }
        //积分
        Integer pointSum = basketInfoList.stream().map(BasketInfo::getGrantedShopPoint).reduce(0, Integer::sum);
        platformOrderDo.setPoint(BigDecimal.valueOf(pointSum));
        Collection<BasketInfo> values = basketInfoList.stream().collect(Collectors.toMap(BasketInfo::getProductCustomCode, val -> val, (o1, o2) -> {
            o1.setAmount(o1.getAmount() + o2.getAmount());
            o1.setPrice(o1.getPrice() + o2.getPrice());
            return o1;
        })).values();
        platformOrderDo.setPlatformSku(values.stream().map(item -> item.getProductCustomCode() + "*" + item.getAmount()).collect(Collectors.joining(";")));
        for (BasketInfo basketInfo : values) {
            PlatformOrderProductDo orderProductDo = new PlatformOrderProductDo();
            orderProductDo.setOrderId(platformOrderDo.getId());
            orderProductDo.setPlatformOrderNo(platformOrderDo.getPlatformOrderNo());
            orderProductDo.setPlatformProductName(basketInfo.getProductName());
            orderProductDo.setPlatformSku(basketInfo.getProductCustomCode());
            orderProductDo.setPlatformQty(basketInfo.getAmount());
            orderProductDo.setSku(basketInfo.getProductCustomCode());
            orderProductDo.setQty(basketInfo.getAmount());
            orderProductDo.setItemAmount(BigDecimal.valueOf(basketInfo.getPrice()));
            orderProductDo.setCurrencyCode(CountryEnum.JP.getCurrency());
            orderProductDo.setSkuType(1);
            if (Objects.nonNull(platformOrderDo.getId())) {
                platUpdateItems.add(orderProductDo);
            } else {
                platInsetItems.add(orderProductDo);
            }
        }
    }

    @Override
    public void consumerUpdate(MakeShopOrderUpdateConsumerReq req) {
        for (PlatformOrderDo platformOrderDo : req.getPlatformOrderDoList()) {
            platformOrderDao.updateById(platformOrderDo);
        }
        //子表处理
//        List<Long> orderIds = req.getProducts().stream().map(PlatformOrderProductDo::getOrderId).distinct().collect(Collectors.toList());
//        if (orderIds.isEmpty()) {
//            return;
//        }
//        //匹配系统sku
//        platformOrderService.matchSystemSku(req.getProducts(), req.getStoreId(), req.getCompanyId(), req.getTenantId());
//        platformOrderProductDao.delete(new LambdaQueryWrapper<PlatformOrderProductDo>().in(PlatformOrderProductDo::getOrderId, orderIds));
//        List<List<PlatformOrderProductDo>> partition = ListUtil.partition(req.getProducts(), 2000);
//        for (List<PlatformOrderProductDo> orderProductDoList : partition) {
//            platformOrderProductDao.insertPlatformOrderItems(orderProductDoList);
//        }
    }

    @Override
    public void markShip(MakeShopMarkShipConsumerReq req) throws Exception {
        if (CollUtil.isEmpty(req.getUpdateOrderAttributes())) {
            return;
        }
        PlatformStoreDo storeDo = platformStoreDao.selectById(req.getStoreId());
        Map<String, UpdateOrderAttribute> platNoMatchOrderAttribute = req.getUpdateOrderAttributes().stream().collect(Collectors.toMap(UpdateOrderAttribute::getDisplayOrderNumber, val -> val, (o1, o2) -> o1));
        //获取平台订单号
        Set<String> platNoSet = req.getUpdateOrderAttributes().stream().map(UpdateOrderAttribute::getDisplayOrderNumber).filter(StrUtil::isNotBlank).collect(Collectors.toSet());
        Map<String, Long> platNoMatchId = new HashMap<>();
        if (CollUtil.isNotEmpty(platNoSet)) {
            platNoMatchId = platformOrderService.lambdaQuery()
                    .in(PlatformOrderDo::getPlatformOrderNo, platNoSet)
                    .eq(PlatformOrderDo::getPlatformCode, StaticDict.Store_PlatformCode.Makeshop.getValue()).list().stream().collect(Collectors.toMap(PlatformOrderDo::getPlatformOrderNo, PlatformOrderDo::getId, (o1, o2) -> o2));
        }
        if (storeDo == null || StringUtils.isBlank(storeDo.getShopUrl()) || StringUtils.isBlank(storeDo.getAppKey()) || StringUtils.isBlank(storeDo.getServiceToken())) {
            String msg = "店铺未通过Make Shop授权,标发失败";
            platformOrderService.updateMarkStatus(new ArrayList<>(platNoMatchId.values()), 2, msg);
            throw new Exception(msg);
        }
        ResultAttributtes[] resultAttributtes = GraphqlResultAttributesBuilder.build(UpdateOrderAttributeResponse.class);
        //批量处理防止标发数据过大，请求超5M的情况
        List<List<UpdateOrderAttribute>> partition = ListUtil.partition(req.getUpdateOrderAttributes(), 1000);
        List<UpdateOrderAttributeResult> failResultList = new ArrayList<>();
        List<OperateRecordDo> operateRecordDos = new ArrayList<>();
        try {
            for (List<UpdateOrderAttribute> updateOrderAttributeList : partition) {
                UpdateOrderAttributeRequest updateOrderAttributeRequest = new UpdateOrderAttributeRequest();
                updateOrderAttributeRequest.setUpdateOrderAttributes(updateOrderAttributeList);
                Map<String, Object> request = new HashMap<>(2);
                request.put("input", new RequestObjectParameter(updateOrderAttributeRequest));
                UpdateOrderAttributeResponse response = MakeShopGraphqlUtils.postGraphqlMutation(MakeShopShopConfig.builder().url(storeDo.getShopUrl()).apiKey(storeDo.getAppKey()).token(storeDo.getServiceToken()).build(), "updateOrderAttribute", request, UpdateOrderAttributeResponse.class, resultAttributtes);
                if (response != null && CollUtil.isNotEmpty(response.getUpdateOrderAttributeResults())) {
                    //message不为空的订单为失败的情况
                    List<UpdateOrderAttributeResult> resultList = response.getUpdateOrderAttributeResults().stream().filter(item -> StrUtil.isNotBlank(item.getMessage())).collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(resultList)) {
                        failResultList.addAll(resultList);
                    }
                }
            }
        } catch (Exception e) {
            platformOrderService.updateMarkStatus(new ArrayList<>(platNoMatchId.values()), 2, "连接makeshop系统超时，标发失败");
            throw new Exception("店铺【" + storeDo.getStoreName() + "】标发失败:" + e.getMessage());
        }
        //处理标发失败
        if (CollUtil.isNotEmpty(failResultList)) {
            for (UpdateOrderAttributeResult updateOrderAttributeResult : failResultList) {
                Long platId = platNoMatchId.get(updateOrderAttributeResult.getDisplayOrderNumber());
                if (platId == null) {
                    continue;
                }
                OperateRecordDo operateRecordDo = new OperateRecordDo(platId, OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_MarkShip_Fail, req.getUserId(), new Date(), updateOrderAttributeResult.getMessage());
                operateRecordDos.add(operateRecordDo);
                platformOrderService.updateMarkStatus(Collections.singletonList(platId), 2, updateOrderAttributeResult.getMessage());
            }
            platNoSet.removeAll(failResultList.stream().map(UpdateOrderAttributeResult::getDisplayOrderNumber).collect(Collectors.toSet()));
        }
        //处理标发成功的订单
        if (CollUtil.isNotEmpty(platNoSet)) {
            List<Long> successId = new ArrayList<>();
            for (String platNo : platNoSet) {
                Long id = platNoMatchId.get(platNo);
                if (id == null) {
                    continue;
                }
                successId.add(id);
                //TODO 目前暂定标发第一个单号
                String trackNo = "";
                UpdateOrderAttribute updateOrderAttribute = platNoMatchOrderAttribute.get(platNo);
                if (updateOrderAttribute != null) {
                    List<DeliveryRequestInfoForUpdate> deliveryRequestInfos = updateOrderAttribute.getDeliveryRequestInfos();
                    if (CollUtil.isNotEmpty(deliveryRequestInfos)) {
                        DeliveryRequestInfoForUpdate deliveryInfo = deliveryRequestInfos.get(0);
                        trackNo = deliveryInfo.getSlipNumber();
                    }
                }
                OperateRecordDo operateRecordDo = new OperateRecordDo(id, OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_MarkShip, req.getUserId(), new Date(), trackNo);
                operateRecordDos.add(operateRecordDo);
            }
            platformOrderService.updateMarkStatusForFinish(successId, 3, null, StaticDict.Store_PlatformCode.Makeshop.getValue());
            //回传单号后 去标记订单已完成
            rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_MakeShop_MarkStatus, JSON.toJSONString(new MakeShopMarkStatusConsumerReq(platNoSet, storeDo, req.getUserId(), DeliveryStatus.COMPLETED, false)));
        }
        //操作记录
        if (CollUtil.isNotEmpty(operateRecordDos)) {
            List<List<OperateRecordDo>> operatePartition = ListUtil.partition(operateRecordDos, 3000);
            for (List<OperateRecordDo> partList : operatePartition) {
                rabbitTemplate.convertAndSend(RabbitQueueConstant.CrossMall_CMOrder_OperateList, JSON.toJSONString(partList));
            }
        }
    }

    @Override
    public void markOrderStatus(MakeShopMarkStatusConsumerReq req) throws Exception {
        Collection<String> platNoList = req.getPlatNoList();
        if (CollUtil.isEmpty(platNoList)) {
            return;
        }
        PlatformStoreDo storeDo = req.getStoreDo();
        Map<String, PlatformOrderDo> platNoMatchDo = platformOrderService.lambdaQuery()
                .in(PlatformOrderDo::getPlatformOrderNo, platNoList)
                .eq(PlatformOrderDo::getPlatformCode, StaticDict.Store_PlatformCode.Makeshop.getValue()).list().stream().collect(Collectors.toMap(PlatformOrderDo::getPlatformOrderNo, val -> val, (o1, o2) -> o2));
        if (storeDo == null || StringUtils.isBlank(storeDo.getShopUrl()) || StringUtils.isBlank(storeDo.getAppKey()) || StringUtils.isBlank(storeDo.getServiceToken())) {
            String msg = "店铺未通过Make Shop授权,无法标记订单状态";
            platformOrderService.lambdaUpdate()
                    .in(PlatformOrderDo::getId, platNoMatchDo.values().stream().map(PlatformOrderDo::getId).collect(Collectors.toList()))
                    .set(PlatformOrderDo::getMarkShipmentFailReason, msg)
                    .set(PlatformOrderDo::getMarkFinishStatus, 2)
                    .update();
            throw new Exception(msg);
        }
        ResultAttributtes[] resultAttributtes = GraphqlResultAttributesBuilder.build(UpdateOrderAttributeResponse.class);
        List<OperateRecordDo> operateRecordDos = new ArrayList<>();
        List<UpdateOrderDeliveryStatusResult> failResultList = new ArrayList<>();
        List<List<String>> partition = ListUtil.partition(new ArrayList<>(platNoList), 2000);
        try {
            for (List<String> platNos : partition) {
                List<UpdateOrderDeliveryStatus> updateOrderDeliveryStatuses = new ArrayList<>();
                for (String platNo : platNos) {
                    PlatformOrderDo platformOrderDo = platNoMatchDo.get(platNo);
                    UpdateOrderDeliveryStatus updateOrderDeliveryStatus = new UpdateOrderDeliveryStatus();
                    updateOrderDeliveryStatus.setDisplayOrderNumber(platNo);
                    updateOrderDeliveryStatus.setDeliveryStatus(req.getDeliveryStatus());
                    if (platformOrderDo != null) {
                        updateOrderDeliveryStatus.setDeliveryId(platformOrderDo.getBasketId());
                        if (req.isReturnStockAndPoint() && StaticDict.Platform_Order_Status.Four.getValue().equals(platformOrderDo.getStatus()) && DeliveryStatus.NOT_YET.equals(req.getDeliveryStatus())) {
                            updateOrderDeliveryStatus.setIsReturnStock(true);
                            updateOrderDeliveryStatus.setIsReturnPoint(true);
                        }
                    }
                    updateOrderDeliveryStatuses.add(updateOrderDeliveryStatus);
                }
                UpdateOrderDeliveryStatusRequest updateOrderDeliveryStatusRequest = new UpdateOrderDeliveryStatusRequest();
                updateOrderDeliveryStatusRequest.setUpdateOrderDeliveryStatusRequests(updateOrderDeliveryStatuses);
                Map<String, Object> request = new HashMap<>(2);
                request.put("input", new RequestObjectParameter(updateOrderDeliveryStatusRequest));
                UpdateOrderDeliveryStatusResponse response = MakeShopGraphqlUtils.postGraphqlMutation(MakeShopShopConfig.builder().url(storeDo.getShopUrl()).apiKey(storeDo.getAppKey()).token(storeDo.getServiceToken()).build(), "updateOrderDeliveryStatus", request, UpdateOrderDeliveryStatusResponse.class, resultAttributtes);
                if (response != null && CollUtil.isNotEmpty(response.getUpdateOrderDeliveryStatusResults())) {
                    //message不为空的订单为失败的情况
                    List<UpdateOrderDeliveryStatusResult> resultList = response.getUpdateOrderDeliveryStatusResults().stream().filter(item -> StrUtil.isNotBlank(item.getMessage())).collect(Collectors.toList());
                    if (CollUtil.isNotEmpty(resultList)) {
                        failResultList.addAll(resultList);
                    }
                }
            }
        } catch (Exception e) {
            platformOrderService.lambdaUpdate()
                    .in(PlatformOrderDo::getId, platNoMatchDo.values().stream().map(PlatformOrderDo::getId).collect(Collectors.toList()))
                    .set(PlatformOrderDo::getMarkShipmentFailReason, "连接makeshop系统超时，无法标记订单状态")
                    .set(PlatformOrderDo::getMarkFinishStatus, 2)
                    .update();
            throw new Exception("店铺【" + storeDo.getStoreName() + "】无法标记订单状态:" + e.getMessage());
        }
        //处理标发失败
        if (CollUtil.isNotEmpty(failResultList)) {
            for (UpdateOrderDeliveryStatusResult deliveryStatusResult : failResultList) {
                PlatformOrderDo platformOrderDo = platNoMatchDo.get(deliveryStatusResult.getDisplayOrderNumber());
                if (platformOrderDo == null) {
                    continue;
                }
                OperateRecordDo operateRecordDo = new OperateRecordDo(platformOrderDo.getId(), OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_MarkFinish_Fail, req.getUserId(), new Date(), req.getDeliveryStatus().getValue() + SysConstant.operateRecordSeparator + deliveryStatusResult.getMessage());
                operateRecordDos.add(operateRecordDo);
                platformOrderService.lambdaUpdate()
                        .eq(PlatformOrderDo::getId, platformOrderDo.getId())
                        .set(PlatformOrderDo::getMarkShipmentFailReason, deliveryStatusResult.getMessage())
                        .set(PlatformOrderDo::getMarkFinishStatus, 2)
                        .update();
            }
            platNoList.removeAll(failResultList.stream().map(UpdateOrderDeliveryStatusResult::getDisplayOrderNumber).collect(Collectors.toSet()));
        }
        //处理标发成功的订单
        if (CollUtil.isNotEmpty(platNoList)) {
            List<Long> successId = new ArrayList<>();
            for (String platNo : platNoList) {
                PlatformOrderDo platformOrderDo = platNoMatchDo.get(platNo);
                if (platformOrderDo == null) {
                    continue;
                }
                successId.add(platformOrderDo.getId());
                OperateRecordDo operateRecordDo = new OperateRecordDo(platformOrderDo.getId(), OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_MarkFinish, req.getUserId(), new Date(), req.getDeliveryStatus().getValue());
                operateRecordDos.add(operateRecordDo);
            }
            if (CollUtil.isNotEmpty(successId)) {
                platformOrderService.lambdaUpdate()
                        .in(PlatformOrderDo::getId, successId)
                        .set(PlatformOrderDo::getMarkShipmentFailReason, null)
                        .set(PlatformOrderDo::getMarkFinishStatus, 3)
                        .set(PlatformOrderDo::getMarkShipmentTime, new Date())
                        .update();
            }
        }
        //操作记录
        if (CollUtil.isNotEmpty(operateRecordDos)) {
            List<List<OperateRecordDo>> operatePartition = ListUtil.partition(operateRecordDos, 3000);
            for (List<OperateRecordDo> partList : operatePartition) {
                rabbitTemplate.convertAndSend(RabbitQueueConstant.CrossMall_CMOrder_OperateList, JSON.toJSONString(partList));
            }
        }
    }

    @Override
    public void markFinish() {
        List<PlatformOrderDo> platformOrderDoList = platformOrderDao.selectList(Wrappers.<PlatformOrderDo>lambdaQuery().select(PlatformOrderDo::getId, PlatformOrderDo::getPlatformOrderNo, PlatformOrderDo::getMarkFinishStatus, PlatformOrderDo::getStoreId).eq(PlatformOrderDo::getStatus, 3).eq(PlatformOrderDo::getMarkFinishStatus, 5).eq(PlatformOrderDo::getPlatformCode, StaticDict.Store_PlatformCode.Makeshop.getValue()).gt(PlatformOrderDo::getMarkShipmentTime, DateUtils.dateFormatToString(DateUtils.passingDate(new Date(), -3))));
        Map<Long, List<PlatformOrderDo>> collect = platformOrderDoList.stream().collect(Collectors.groupingBy(PlatformOrderDo::getStoreId));
        for (Map.Entry<Long, List<PlatformOrderDo>> entry : collect.entrySet()) {
            PlatformStoreDo storeDo = platformStoreService.getById(entry.getKey());
            List<PlatformOrderDo> orderDoList = entry.getValue();
            if (CollUtil.isNotEmpty(orderDoList)) {
                rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_MakeShop_MarkStatus, JSON.toJSONString(new MakeShopMarkStatusConsumerReq(orderDoList.stream().map(PlatformOrderDo::getPlatformOrderNo).collect(Collectors.toList()), storeDo, null, DeliveryStatus.COMPLETED, false)));
            }
        }
    }


/**
 * ====================================================加密参数构建====================================================================
 */
    /**
     * 构建header参数
     *
     * @param headerMap
     * @return
     */
    public static Request.Builder createSPHeader(Map<String, String> headerMap) {
        Request.Builder requestBuilder = new Request.Builder();
        Iterator<Map.Entry<String, String>> pairs =
                headerMap.entrySet().iterator();
        while (pairs.hasNext()) {
            Map.Entry<String, String> data = pairs.next();
            requestBuilder.addHeader(data.getKey(), data.getValue());
        }
        return requestBuilder;
    }

}
